<template>
  <div>
    <el-container style="height: 700px">
      <el-aside width="80%">
        <el-button icon="el-icon-info" class="watchXml" @click="watchXML">查看xml</el-button>
        <el-button icon="el-icon-check" class="watchXml" @click="saveXML">保存xml</el-button>
        <el-button icon="el-icon-back" class="watchXml" @click="returnBack">返回</el-button>
        <div ref="canvas" style="width: 100%;height: 100%" />
      </el-aside>
      <el-main>
        <el-form label-width="auto" size="mini" label-position="top">
          <!-- 动态显示属性面板 -->
          <component :is="propsComponent" :key="key" :element="element" />
        </el-form>
      </el-main>
    </el-container>
  </div>
</template>

<script>
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'
// 左边工具栏以及编辑节点的样式
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'
// 在这里引入一下Bpmn建模器对象
import BpmnModeler from 'bpmn-js/lib/Modeler'
import customTranslate from './chinese/customTranslate.js'
import bpmnHelper from './custommodel/js/helper/BpmnHelper'
import activitiModdleDescriptor from './custommodel/js/activiti.json'
import CommonProps from './custommodel/components/CommonProps'
import StartEventProps from './custommodel/components/StartEventProps'
import UserTaskProps from './custommodel/components/UserTaskProps'
import SequenceFlowProps from './custommodel/components/SequenceFlowProps'
import EndEventProps from './custommodel/components/EndEventProps'
import { detail, create } from '@neu/dcom-ui/api/workflowDefinition'
// const uuid = require('uuid/v1')
let id = `Default`
let name = '默认名称'
export default {
  components: {
    CommonProps,
    StartEventProps,
    UserTaskProps,
    SequenceFlowProps,
    EndEventProps
  },
  provide: function() {
    return {
      bpmnModeler: this.getBpmnModeler,
      params: this.params
    }
  },
  data() {
    return {
      element: null,
      key: null,
      bpmnModeler: null,
      initTemplate: `<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" 
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" 
targetNamespace="" 
exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
<process id="${id}" name="${name}" >
</process>
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
    <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
    </bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>`,
      propsComponent: 'CommonProps',
      defaultData: {
        'bpmn:StartEvent': '开始',
        'bpmn:EndEvent': '完成',
        'bpmn:IntermediateThrowEvent': '终止'
      },
      rootObj: null
    }
  },
  mounted() {
    if (this.$route.params.hasOwnProperty('isExist')) {
      if (this.$route.params.isExist) {
        detail(this.$route.params.id).then(res => {
          this.initTemplate = res.data.xmlContent
          this.init()
        })
      } else {
        id = this.$route.params.id
        name = this.$route.params.name
        this.initTemplate = this.getInitTemplate(id, name)
        this.init()
      }
    } else {
      this.init()
    }
  },
  methods: {
    getBpmnModeler() {
      return this.bpmnModeler
    },
    watchXML() {
      this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
        if (err) {
          console.error('流程数据生成失败')
          console.log(err)
          return
        }
        console.log(xml)
      })
    },
    init() {
      // 获取画布 element
      this.canvas = this.$refs.canvas
      // 汉化
      const customTranslateModule = {
        translate: ['value', customTranslate]
      }
      // 创建Bpmn对象
      this.bpmnModeler = new BpmnModeler({
        // 设置bpmn的绘图容器为上门获取的画布 element
        container: this.canvas,
        // 添加属性面板，添加翻译模块
        additionalModules: [
          customTranslateModule
        ],
        // 加入工具栏支持
        propertiesPanel: {
          parent: '#js-properties-panel'
        },
        // 模块拓展，拓展activiti的描述
        moddleExtensions: {
          activiti: activitiModdleDescriptor
        }
      })

      this.createNewDiagram(this.initTemplate)
    },
    createNewDiagram(bpmn) {
      const that = this
      // 将xml导入Bpmn-js建模器
      this.bpmnModeler.importXML(bpmn, err => {
        if (err) {
          that.$message({
            showClose: true,
            message: '打开模型出错,请确认该模型符合Bpmn2.0规范',
            type: 'error'
          })
        } else {
          // 初始化element
          const rootId = that.getFilename(bpmn)
          const elementRegistry = that.bpmnModeler.get('elementRegistry')
          const shape = elementRegistry.get(rootId)
          that.rootObj = shape
          that.element = shape
          // this.addModelerListener()
          that.addEventBusListener()
        }
      })
    },
    addModelerListener() {
      // 监听 modeler
      const bpmnjs = this.bpmnModeler
      const that = this
      // 'shape.removed', 'connect.end', 'connect.move'
      const events = ['shape.added', 'connection.removed', 'shape.move.end', 'shape.removed']
      events.forEach(function(event) {
        that.bpmnModeler.on(event, e => {
          var elementRegistry = bpmnjs.get('elementRegistry')
          var shape = e.element ? elementRegistry.get(e.element.id) : e.shape

          // console.log(shape)
          if (event === 'shape.added') {
            // if (defaultActivitiType.includes(shape.type)) {
            console.log('addModelerListener 新增了shape')
            that.key = e.element.id.replace('_label', '')
            that.element = e.element
            that.propsComponent = bpmnHelper.getComponentByEleType(shape.type) === undefined ? that.propsComponent : bpmnHelper.getComponentByEleType(shape.type)
            // }
          } else if (event === 'shape.move.end') {
            console.log('移动了shape')
            that.key = shape.id
            that.element = e.shape
            that.propsComponent = bpmnHelper.getComponentByEleType(shape.type)
          } else if (event === 'shape.removed' || event === 'connection.removed') {
            // alert('11111111111')
            console.log('删除了shape')
          }
        })
      })
    },
    addEventBusListener() {
      // 监听 element
      const that = this
      const eventBus = this.bpmnModeler.get('eventBus')
      const eventTypes = ['element.click', 'element.changed']
      eventTypes.forEach(function(eventType) {
        eventBus.on(eventType, function(e) {
          if (eventType === 'element.changed') {
            that.elementChanged(e)
            // 展示新增图形的属性
            // that.key = e.element.id
            // that.element = e.element
            // that.propsComponent = bpmnHelper.getComponentByEleType(e.element.type)
          } else if (eventType === 'element.click') {
            if (!e || e.element.type === 'bpmn:Process') {
              that.initElement()
            } else {
              // console.log('点击了element')
              // 展示新增图形的属性
              that.key = e.element.id
              that.element = e.element
              that.propsComponent = bpmnHelper.getComponentByEleType(e.element.type)
            }
          }
        })
      })
    },
    initElement() {
      const that = this
      that.key = '1'
      that.element = that.rootObj
      that.propsComponent = 'CommonProps'
    },
    isInvalid(param) { // 判断是否是无效的值
      return param === null || param === undefined || param === ''
    },
    isSequenceFlow(type) { // 判断是否是线
      return type === 'bpmn:SequenceFlow'
    },
    elementChanged(e) {
      const id = e.element.id.replace('_label', '')
      var shape = this.getShape(id)
      this.element = shape
      const that = this

      if (!shape) {
        // 若是shape为null则表示删除, 无论是shape还是connect删除都调用此处
        // console.log('无效的shape')
        // 上面已经用 shape.removed 检测了shape的删除, 要是删除shape的话这里还会被再触发一次
        // console.log('删除了shape和connect')
        that.initElement()
        return
      }
      that.key = e.element.id
      that.element = shape
      that.propsComponent = shape.type === 'bpmn:Process' ? 'CommonProps' : bpmnHelper.getComponentByEleType(shape.type)

      if (!this.isInvalid(shape.type)) {
        if (this.isSequenceFlow(shape.type)) {
          // console.log('改变了线')
        } else {
          that.setDefaultProperties()
        }
      }
    },
    getShape(id) {
      var elementRegistry = this.bpmnModeler.get('elementRegistry')
      return elementRegistry.get(id)
    },
    setDefaultProperties() {
      // console.log('setDefaultProperties')
      const that = this
      const { element } = that
      if (element) {
        // 这里可以拿到当前点击的节点的所有属性
        const { type, businessObject } = element
        const { name } = businessObject
        if (that.verifyIsEvent(type)) {
          const eventType = businessObject.eventDefinitions ? businessObject.eventDefinitions[0]['$type'] : ''
          console.log(eventType)
        } else if (this.verifyIsTask(type)) {
          const taskType = type
          console.log(taskType)
        }
        that.element['name'] = name || that.defaultData[element.type]
      }
    },
    verifyIsEvent(type) {
      return type.includes('Event')
    },
    verifyIsTask(type) {
      return type.includes('Task')
    },
    /** process id */
    getFilename(xml) {
      const start = xml.indexOf('process')
      let filename = xml.substring(start, xml.indexOf('>', start))
      filename = filename.substr(filename.indexOf('id') + 4)
      filename = filename.substr(0, filename.indexOf('"'))
      return filename
    },
    /** process name */
    getProcessname(xml) {
      const start = xml.indexOf('process')
      let filename = xml.substring(start, xml.indexOf('>', start))
      if (filename.indexOf('name') === -1) {
        return null
      }
      filename = filename.substr(filename.indexOf('name') + 6)
      filename = filename.substr(0, filename.indexOf('"'))
      return filename
    },
    saveXML() {
      const that = this
      this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
        if (!err) {
          const processName = that.getProcessname(xml)
          if (!processName) {
            return that.$message({
              showClose: true,
              message: '流程名称不能为空',
              type: 'error'
            })
          }

          // 替换targetNamespace
          const start = xml.indexOf('targetNamespace')
          const end = xml.indexOf('exporter=')
          // const saveXml = xml.substring(0, start - 1) + ` targetNamespace="${processName}" ` + xml.substring(end, xml.length - 1)
          const saveXml = `${xml.substring(0, start - 1)} targetNamespace="${processName}" ${xml.substring(end, xml.length - 1)}`
          const dto = {
            name: `${processName}.bpmn`,
            xmlContent: saveXml
          }
          create(dto).then(res => {
            if (res.status === 'success') {
              that.$message({
                showClose: true,
                message: '保存成功',
                type: 'success'
              })
              return that.returnBack()
            } else {
              return that.$message({
                showClose: true,
                message: res.data,
                type: 'error'
              })
            }
          })
        }
      })
    },
    returnBack() {
      this.$router.push({ name: 'dcom_businessProcessType' })
    },
    getInitTemplate(id, name) {
      return `<?xml version="1.0" encoding="UTF-8"?>
        <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 
        xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 
        xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" 
        xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" 
        targetNamespace="" 
        exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
        <process id="${id}" name="${name}" >
        </process>
        <bpmndi:BPMNDiagram id="BpmnDiagram_1">
            <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
            </bpmndi:BPMNPlane>
        </bpmndi:BPMNDiagram>
        </definitions>`
    }
  }

}
</script>
